Skip to content

修复用户脚本热重载超时与状态确认 - #2916

Closed
130040167 wants to merge 3 commits into
BigPizzaV3:mainfrom
130040167:codex/user-script-hot-reload-reliability-20261105
Closed

130040167 wants to merge 3 commits into
BigPizzaV3:mainfrom
130040167:codex/user-script-hot-reload-reliability-20261105

Conversation

@130040167

@130040167 130040167 commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

现象

页面线程繁忙时,用户脚本热重载可能在等待 CDP Runtime.evaluate 响应时超时。超时不会取消已经发送的页面操作,重复点击可能使多次操作交错;页面恢复或脚本实际加载尚未确认时,也不应显示成功。

修复

  • 通过每个实例的本地 owner 协调热重载,以 owner epoch 和 operation ID 标识操作,串行执行并查询状态。响应超时后保留原操作,待确认时不另起一次重载。
  • 将页面 prepare/apply 与文档、操作和脚本 revision 关联,并使用后台快照与 generation 约束后台停止、脚本应用和迟到请求。
  • 旧脚本无法同步 cleanup 时保留整页刷新路径;不允许刷新页面的请求会明确返回阻止。区分脚本原地更新、页面刷新、页面切换和待确认状态。
  • 启动初始化继续使用独立的幂等加载入口,避免初始化触发重复热重载。页面端仅在桥接明确返回旧版本不支持所需能力时尝试旧接口;超时或响应丢失不会触发跨协议重试。
  • 已合入上游的拓展包删除行为:删除时保留废纸篓处理与配置锁,管理器允许删除未缺失的用户拓展包。

默认行为和接口

本 PR 没有新增默认关闭开关:显式脚本重载默认使用新的 owner 协调路径。上述旧接口回退用于兼容明确不支持新协议的旧桥接,并不是新的默认关闭方案。这样可保留超时后的操作身份,但涉及所有显式重载调用,仍需结合跨平台验收评估。

/user-scripts/reload-operation-v1、/user-scripts/reload-no-page、/user-scripts/reload-status 和 /extensions/services/call-external 是 Codex++ 内部桥接路由,未加入拓展公开路由白名单。

Windows 新增的依赖 feature 用途:

  • Win32_Security:读取进程令牌中的用户信息,并为本地对象设置安全属性。
  • Win32_Security_Authorization:转换用户 SID 和安全描述符,为当前用户创建受限访问控制。
  • Win32_System_Pipes:获取命名管道服务端进程 ID,验证服务端用户身份。

验证

  • 最新 rebase 后 Windows 本地检查:renderer 组装及一致性检查、TypeScript 检查、页面客户端与脚本运行时 44 项测试,以及管理器和 renderer 相关 226 项测试通过。
  • 最新提交 2d168861 的 Windows release 管理器构建通过;独立管理器 WebView 和 Tauri invoke 启动冒烟通过,受保护配置和正式进程身份未变化,测试进程及端口均已退出。
  • 前一次 rebase 后 4d019e30 的 Windows release 管理器构建通过;独立管理器启动、WebView 和 Tauri invoke 冒烟通过,正式实例身份及受保护配置未变化,测试进程和端口均已退出。14085b17 与该提交的文件树完全相同。
  • rebase 前的 2cd8e842:Windows release 管理器构建成功,launcher 重载协调 24 项测试通过。
  • rebase 前的 Windows 真实页面验收:使用独立的打包 Codex 页面和候选管理器的恢复附着路径,先修改脚本文件,再通过管理器原生命令重载、停用和启用。三次重载均在同一页面返回 applied,加载和 cleanup 次数符合预期。
  • rebase 前的 Windows 页面阻塞验收:实际渲染线程阻塞 12 秒期间提交一次重载,同一操作在约 5.4 秒和 11.1 秒的状态为 unknown,页面恢复后返回 applied,仅执行一次 cleanup 和一次加载。
  • 上述两次真实页面验收后,受保护配置及正式实例身份未变化,测试进程和监听端口均已退出。
  • 之前的 Linux CI 失败发生在旧 PR 提交的 upstream_connection_reuse::reused_clients_are_scoped_to_their_runtime 连接计数断言。上游已将该用例移到独立测试程序以避免并行测试挤占全局客户端缓存,该上游修复已包含在当前分支的合并基线中;当前提交的三平台 CI 结果以本 PR 的检查为准。
  • 前一次 rebase 后 4d019e30 的 PR CI 中,Windows 和 macOS 通过,Linux 的 agent_collaboration_queue::mcp_delegations_run_concurrently_up_to_the_limit_and_queue_the_rest 失败:队列中的第三个任务在固定两秒的慢任务结束后才启动。该测试与队列实现和上游 main 相同,上游对应提交的 Linux CI 通过;调度时序可能影响该断言,但这次失败的原因尚未确定。随后在不改变文件树的 14085b17 上重新触发的 PR CI 三平台通过。
  • 最新 rebase 后提交 2d168861 的 PR CI 三平台通过:Linux Rust 测试、DEB 构建及安装校验;Windows 前端、类型检查和 Rust 测试;macOS 通用 DMG 构建及结构校验。此 PR 工作流按配置跳过 Windows 安装包构建。
  • rebase 前提交 2cd8e842 的 PR CI 三项通过:Linux Rust 测试、DEB 构建及安装校验;Windows 前端、类型检查和 Rust 测试;macOS 通用 DMG 构建及结构校验。此 PR 工作流按配置跳过 Windows 安装包构建。rebase 后的 CI 以当前 PR 检查为准。

验收边界

  • 两次新增 Windows 真实页面测试覆盖管理器原生命令与实际页面,但未覆盖管理器发起的多开进程创建、正式包启动 wrapper 或管理器按钮点击。
  • Linux 桌面实例端到端热重载、Unix 可执行 helper 和新版拓展图标栏详情页开关仍待对应环境验收;macOS 的实际桌面热重载也需要进一步验收。
  • 此修复不能抢占无终止条件的同步脚本;页面不响应时保持待确认,不将通信超时视为脚本已停止。

@BigPizzaV3

Copy link
Copy Markdown
Owner

感谢!看过了:和 main 无冲突,Windows / macOS CI 通过,但 Linux 红:upstream_connection_reuse::reused_clients_are_scoped_to_their_runtime 断言连接数为 3、预期为 2。main 自身这个用例是绿的,你那边 fork 重跑是绿的,但原因没查清,暂时还不能排除和这个 PR 有关(新的控制通道会不会多建一条连接)。请先确认一下,或者 rebase 到最新 main 再跑一次 CI。

另外几点合入前要对齐:

  1. 这个改动很大(+4572),重写了 /user-scripts/reload,所有用户的脚本重载默认都会走新路径。能否先默认关闭、或者保留旧路径作为回退?
  2. crates/codex-plus-core/Cargo.toml 新增了 Win32_Security、Win32_Security_Authorization、Win32_System_Pipes 三个 Windows features,请在描述里说明各自的用途。
  3. 新增的桥接路由 /user-scripts/reload-no-page、/user-scripts/reload-status、/extensions/services/call-external 不在拓展白名单里,这是对的;请在描述里确认它们只给 Codex++ 自己用、不打算开放给拓展。

@BigPizzaV3

Copy link
Copy Markdown
Owner

感谢修复,验证记录也很详细。目前有两件事需要处理:

  1. 冲突:main 合了 [Feature]:2.3.0新增万物皆拓展,但拓展安装后不可以删除 #2919(拓展包整个文件夹移进废纸篓),和这里有两处冲突,麻烦 rebase 到最新 main:

    • user_scripts.rs:main 已把 delete_user_script 拆成包装函数加 delete_user_script_with_trash(key, trash_dir)。请保留这个拆分,把新加的 config_lock / config_file_lock() 两行放到 delete_user_script_with_trash 开头。
    • App.tsx 的 canDelete:main 现在允许删除拓展包,请合成 codexHost && script.source === "user" && !script.missing,不要再带 !isPackage。

    rebase 后请再跑一次 node scripts/assemble-renderer-inject.mjs 确认产物一致。

  2. CI:Linux 上失败的 upstream_connection_reuse::reused_clients_are_scoped_to_their_runtime(3 ≠ 2)和你的分析一致:全局 client 缓存(上限 32)在并行用例下可能被挤掉,属于 main 上测试本身不稳定,不算这个 PR 的问题,我们会在 main 单独修,你不用为它改代码。

这个 PR 规模比较大(+4.5k),合并前我们会在 macOS 上实际验一遍热重载。Linux 桌面端到端和新版拓展图标栏这两项,如果后续有条件补上验收,也欢迎在这里同步。

BigPizzaV3 added a commit that referenced this pull request Nov 6, 2026
进程级转发 client 缓存最多 32 个、键里带运行时 id;在合并的 tests/all 里,上千个并行用例
各自起运行时往同一缓存里塞 client,会在两次请求之间把这个用例的 client 挤掉,多建一条连接,
CI 上偶发 2≠1、3≠2(Linux 连续两次红在这里,#2916 也被它拖红)。按约定单独留在 tests/ 下。
@BigPizzaV3

Copy link
Copy Markdown
Owner

这个 PR 目前有两个问题,暂时无法合并:

  1. 合并冲突:分支与 main 已冲突(mergeStateStatus: DIRTY / CONFLICTING),需要 rebase 或 merge main 后解决。
  2. Linux CI 失败:Linux DEB job 未通过(Windows / macOS 通过)。

改动方向(owner 控制通道、operation ID/epoch、CDP 超时不重复执行、脚本 revision/generation、页面确认)看起来是对的,但请先 rebase 到最新 main、修掉 Linux 失败后我再复审。

@BigPizzaV3

Copy link
Copy Markdown
Owner

感谢!冲突和 Linux 失败都已解决,三平台 CI 通过,描述里也补齐了默认路径、三个 Windows feature 的用途和内部路由的说明。

按之前说的,这个改动覆盖所有用户的显式脚本重载路径(现在 +8k),合并前我们要在 macOS 上实际验一遍热重载(修改、停用、启用,以及页面繁忙时的待确认状态)。这一轮还没来得及验,先保留,验完会在这里给结论。

@BigPizzaV3

Copy link
Copy Markdown
Owner

main 这两天又合了一批(#2911 等),这里重新出现冲突了,方便的时候请 rebase 一下。macOS 实测热重载这一步仍在我这边,还没做完,所以先继续保持开启。

@130040167
130040167 force-pushed the codex/user-script-hot-reload-reliability-20261105 branch 2 times, most recently from 4d019e3 to 14085b1 Compare November 9, 2026 15:27
@130040167
130040167 force-pushed the codex/user-script-hot-reload-reliability-20261105 branch from 14085b1 to 2d16886 Compare November 10, 2026 15:07
@BigPizzaV3

Copy link
Copy Markdown
Owner

感谢投入这么多精力排查热重载超时!这个 PR 体量比较大(8k+ 行),引入了一套新的 IPC 协调架构,还夹带了拓展删除、多开改写 config.toml、后端服务调用的 source 校验等其他改动,我们这边不太好评审和维护。几个具体风险:

  1. launcher/main.rs:1424 的 start_native_control(debug_port)? 一旦失败,整个注入都会跟着失败。macOS 的 $TMPDIR 路径超过 socket 路径 104 字节上限时,会回落到共享的 /tmp/codex-plus-reload-<uid>;其他本机用户预先建好这个目录,就能让 Codex++ 失效。
  2. 旧的直接 CDP 重载路径被删掉了,没有回退。launcher 是旧版本、或者 manager 和 launcher 的 STATE_DIR 不一致时,重载会直接失败。
  3. user_script_reload.rs 210–219 行、281–293 行拿着全局锁无限重试,一个页面卡住,之后所有重载都会被堵住。

如果方便的话,欢迎拆成更小的 PR:先做 launcher 侧的重载串行化 + 操作 ID + 状态轮询,同时保留旧 CDP 路径作为回退;其他改动各自独立提交。

@130040167 130040167 closed this Nov 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants